import { computed, ref, watch, defineComponent, h } from "vue"
import { cloneDeep, debounce } from "lodash-es"
import { defHttp } from "/@/utils/http/axios"
import { filterDictText } from "/@/utils/dict/JDictSelectUtil"
import { ajaxGetDictItems, getDictItemsByCode } from "/@/utils/dict"
import { JVxeComponent } from "/@/components/jeecg/JVxeTable/types"
import { dispatchEvent } from "/@/components/jeecg/JVxeTable/utils"
import { useResolveComponent as rc } from "/@/components/jeecg/JVxeTable/hooks"
import { useJVxeComponent, useJVxeCompProps } from "/@/components/jeecg/JVxeTable/hooks"
import { useMessage } from "/@/hooks/web/useMessage"
import { loadDictByKeyword } from "/@/api/infra/dict"

/** value - label map，防止重复查询（刷新清空缓存） */
const LabelMap = new Map<string, any>()
// 请求id
let requestId = 0

/** 显示组件，自带翻译 */
export const DictSearchSpanCell = defineComponent({
  name: "JVxeSelectSearchSpanCell",
  props: useJVxeCompProps(),
  setup(props: JVxeComponent.Props) {
    const { innerOptions, innerSelectValue, innerValue } = useSelectDictSearch(props)
    return () => {
      return h("span", {}, [filterDictText(innerOptions.value, innerSelectValue.value || innerValue.value)])
    }
  },
})

// 输入选择组件
export const DictSearchInputCell = defineComponent({
  name: "JVxeSelectSearchInputCell",
  props: useJVxeCompProps(),
  setup(props: JVxeComponent.Props) {
    const { createMessage } = useMessage()
    const { dict, loading, isAsync, options, innerOptions, originColumn, cellProps, innerSelectValue, handleChangeCommon } =
      useSelectDictSearch(props)
    const hasRequest = ref(false)
    // 提示信息
    const tipsContent = computed(() => {
      return originColumn.value.tipsContent || "请输入搜索内容"
    })
    // 筛选函数
    const filterOption = computed(() => {
      if (isAsync.value) {
        //lingyang-boot-vue3/issues/I5QRT8】JVxeTypes.selectDictSearch sync问题
        return () => true
      }
      return (input, option) => option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
    })

    /** 加载数据 */
    const loadData = debounce((value) => {
      const currentRequestId = ++requestId
      loading.value = true
      innerOptions.value = []
      if (value == null || value.trim() === "") {
        loading.value = false
        hasRequest.value = false
        return
      }
      // 字典code格式：table,text,code
      hasRequest.value = true
      loadDictByKeyword(dict.value, value)
        .then((res) => {
          if (currentRequestId !== requestId) {
            return
          }
          const { success, data: result, message } = res
          if (success) {
            innerOptions.value = result
            result.forEach((item) => {
              LabelMap.set(item.value, [item])
            })
          } else {
            createMessage.warning(message || "查询失败")
          }
        })
        .finally(() => {
          loading.value = false
        })
    }, 300)

    function handleChange(selectedValue) {
      innerSelectValue.value = selectedValue
      handleChangeCommon(innerSelectValue.value)
    }

    function handleSearch(value) {
      if (isAsync.value) {
        // 在输入时也应该开启加载，因为loadData加了消抖，所以会有800ms的用户主观上认为的卡顿时间
        loading.value = true
        if (innerOptions.value.length > 0) {
          innerOptions.value = []
        }
        loadData(value)
      }
    }

    function renderOptionItem() {
      const optionItems: any[] = []
      options.value.forEach(({ value, text, label, title, disabled }) => {
        optionItems.push(
          h(
            rc("a-select-option"),
            {
              key: value,
              value: value,
              disabled: disabled || false,
            },
            {
              default: () => text || label || title,
            }
          )
        )
      })
      return optionItems
    }

    return () => {
      return h(
        rc("a-select"),
        {
          ...cellProps.value,
          value: innerSelectValue.value,
          filterOption: filterOption.value,
          showSearch: true,
          allowClear: true,
          autofocus: true,
          defaultOpen: true,
          style: "width: 100%",
          onSearch: handleSearch,
          onChange: handleChange,
        },
        {
          default: () => renderOptionItem(),
          notFoundContent: () => {
            if (loading.value) {
              return h(rc("a-spin"), { size: "small" })
            } else if (hasRequest.value) {
              return h("div", "没有查询到任何数据")
            } else {
              return h("div", [tipsContent.value])
            }
          },
        }
      )
    }
  },
  // 【组件增强】注释详见：JVxeComponent.Enhanced
  enhanced: {
    aopEvents: {
      editActived({ $event }) {
        dispatchEvent({
          $event,
          props: this.props,
          className: ".ant-select .ant-select-selection-search-input",
          isClick: false,
          handler: (el) => el.focus(),
        })
      },
    },
  } as JVxeComponent.EnhancedPartial,
})

function useSelectDictSearch(props) {
  const setup = useJVxeComponent(props)
  const { innerValue, originColumn } = setup

  // 加载状态
  const loading = ref(false)
  // 内部选择值
  const innerSelectValue = ref(null)
  // 内部 options
  const innerOptions = ref<any[]>([])

  const dict = computed(() => originColumn.value.dict)
  // 是否是异步模式
  const isAsync = computed(() => {
    const isAsync = originColumn.value.async
    return isAsync != null && isAsync !== "" ? !!isAsync : true
  })
  const options = computed(() => {
    if (isAsync.value) {
      return innerOptions.value
    } else {
      return originColumn.value.options || []
    }
  })

  /** 公共属性监听 */
  watch(
    innerValue,
    (value: string) => {
      if (value == null || value === "") {
        innerSelectValue.value = null
      } else {
        loadDataByValue(value)
      }
    },
    { immediate: true }
  )
  watch(dict, () => loadDataByDict())

  // 根据 value 查询数据，用于回显
  async function loadDataByValue(value) {
    if (isAsync.value) {
      if (innerSelectValue.value !== value) {
        if (LabelMap.has(value)) {
          innerOptions.value = cloneDeep(LabelMap.get(value))
        } else {
          const result = await loadDictByKeyword(dict.value, value, true)
          if (result && result.length > 0) {
            innerOptions.value = [{ value: value, text: result[0].label }]
            LabelMap.set(value, cloneDeep(innerOptions.value))
          }
        }
      }
    }
    innerSelectValue.value = (value || "").toString()
  }

  // 初始化字典
  async function loadDataByDict() {
    if (!isAsync.value) {
      // 如果字典项集合有数据
      if (!originColumn.value.options || originColumn.value.options.length === 0) {
        // 根据字典Code, 初始化字典数组
        let dictStr = ""
        if (dict.value) {
          const arr = dict.value.split(",")
          if (arr[0].indexOf("where") > 0) {
            const tbInfo = arr[0].split("where")
            dictStr = tbInfo[0].trim() + "," + arr[1] + "," + arr[2] + "," + encodeURIComponent(tbInfo[1])
          } else {
            dictStr = dict.value
          }
          if (dict.value.indexOf(",") === -1) {
            //优先从缓存中读取字典配置
            const cache = getDictItemsByCode(dict.value)
            if (cache) {
              innerOptions.value = cache
              return
            }
          }
          const { success, result } = await ajaxGetDictItems(dictStr, null)
          if (success) {
            innerOptions.value = result
          }
        }
      }
    }
  }

  return {
    ...setup,
    loading,
    innerOptions,
    innerSelectValue,
    dict,
    isAsync,
    options,
  }
}
